﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Diagnostics.Contracts;

namespace ReactiveCode.Linq
{
    class LatestEnumerable<T>: ReadOnlyObservableCollection<IObservable<T>>, IObservableEnumerable<T>, IDisposable
    {
        IDisposable _subscription;
        IEnumerableSubject<T> _listeners;

        public LatestEnumerable(IObservableEnumerable<T> source)
            :base(new ObservableCollection<IObservable<T>>())
        {
            Contract.Requires(source != null);
            _subscription = source.SubscribeWithClear(
                onAdded: (item, index) =>
                {
                    if (index < 0 || index >= Count)
                        index = Count;
                    Items.Insert(index, item);
                    if (_listeners != null)
                        _listeners.OnAdded(item, index);
                },
                onRemoved: (x, index) =>
                {
                    if (index < 0 || index >= Count || this[index] != x)
                        index = Items.IndexOf(x);
                    if (index < 0)
                        return;
                    Items.RemoveAt(index);
                    if (_listeners != null)
                        _listeners.OnRemoved(x, index);
                }, 
                onCleared: delegate
                {
                    Items.Clear();
                    if (_listeners != null)
                        _listeners.OnCleared();
                });
        }
        public void Dispose()
        {
            if (_listeners != null)
                _listeners.OnCompleted();
            _subscription.Dispose();
        }

        public IDisposable Subscribe(IEnumerableObserver<T> observer)
        {
            if (_listeners == null)
                _listeners = new EnumerableSubject<T>();
            return _listeners.Subscribe(observer);
        }

    }
}
